--[[
    This code is responsible for managing all modules' and libraries' creations.  
    It is the glue for the rest of my addons.
--]]

-- global variables!
AsheylaLib = {};
AsheylaLib_Settings = {};
ASHEYLALIB_ACTIVE_PROFILE = "Default";

AsheylaLib.events = {};

-- holds all the libraries
local libraries = {};

-- holds all the modules created
local modules = {};

-- counts the modules
local counter = 0;

-- returns the version
function AsheylaLib:ReturnVersion()
    return GetAddOnMetadata("DoTimer", "Version");
end

-- returns the date uploaded
function AsheylaLib:ReturnDateUploaded()
    return GetAddOnMetadata("DoTimer", "X-Date");
end

function AsheylaLib:SetActiveProfile(name)
    ASHEYLALIB_ACTIVE_PROFILE = name;
    AsheylaLib_Settings[ASHEYLALIB_ACTIVE_PROFILE] = AsheylaLib_Settings[ASHEYLALIB_ACTIVE_PROFILE] or {};
    for module in pairs(modules) do
        module:UpdateSettings();
    end
    self:ProfileUpdate();
end

function AsheylaLib:CopyFromProfile(name, module)
    if AsheylaLib_Settings[name] then
        if module then
            AsheylaLib_Settings[ASHEYLALIB_ACTIVE_PROFILE][module] = libraries["CoreLib"].funcs.CopyTable(nil, AsheylaLib_Settings[name][module]);
        else
            AsheylaLib_Settings[ASHEYLALIB_ACTIVE_PROFILE] = libraries["CoreLib"].funcs.CopyTable(nil, AsheylaLib_Settings[name]);
        end
        for module in pairs(modules) do
            module:UpdateSettings();
        end
    end
    self:ProfileUpdate();
end

function AsheylaLib:ProfileUpdate()

end

function AsheylaLib:ClearAllSettings()
    AsheylaLib_Settings[ASHEYLALIB_ACTIVE_PROFILE] = {};
    for module in pairs(modules) do
        module:UpdateSettings();
    end
    self:ProfileUpdate();
end

function AsheylaLib:InSimpleMode()
    if AsheylaLib_Settings.simpleMode == nil then
        AsheylaLib_Settings.simpleMode = true;
        self:AlertUser("DoTimer is currently in Simple Mode.  Many of its complex features have been disabled.  To disable Simple Mode, go to DoTimer -> Extra and uncheck the check button.");
        return true;
    else
        return AsheylaLib_Settings.simpleMode;
    end
end

function AsheylaLib:SetSimpleMode(bool)
    AsheylaLib_Settings.simpleMode = bool;
    for module in pairs(modules) do
        module:UpdateSettings();
    end
end

-- returns the file path for extra files
function AsheylaLib:GetPath()
    return filepath
end

-- called by modules to initiate themselves
function AsheylaLib:NewModule(name, ...)
    counter = counter + 1;
    
    -- init the module
    local module = {};
    
    -- create the workspace for the module's libraries
    module.libraries = {};
    
    -- add it to the list of modules
    modules[module] = 1;
    
    -- every module gets CoreLib! yay
    AsheylaLib:AddLibrary(module,"CoreLib");
    
    -- give it a name!
    module.libraries["CoreLib"].name = name or "ASHEYLALIBMODULE"..counter;
    module.libraries["CoreLib"].defaultSettings = {};
    
    -- add in all the specified libraries
    for i = 1,select("#", ...) do
        local library = select(i, ...);
        AsheylaLib:AddLibrary(module, library);
    end
    
    return module;
end

-- called by libraries to alert of their existence
function AsheylaLib:CreateLibrary(str, library, init)
    libraries[str] = {funcs = library, init = init};
end

function AsheylaLib:GetLibrary(lib)
    return libraries[lib].funcs;
end

-- adds a library to a module
function AsheylaLib:AddLibrary(module, library)
    -- lib will exist if it has been initialized
    local lib = libraries[library];
    
    if (lib) then
        -- give the module its workspace
        module.libraries[library] = {};
        -- copy in all the module's functions
        for i,v in pairs(lib.funcs) do
            module[i] = v;
        end
        
        -- call the library's init function, if specified
        if (lib.init) then
            lib.init(module);
        end
    end
end

-- calls an event; all modules who have registered it and have an OnEvent Script will have the script called
function AsheylaLib:CallEvent(event, ...)
    local eventTable = self.events[event];
    if eventTable then
        for module, func in pairs(eventTable) do
            if (type(func) ~= "function") then
                func = module:GetScript("OnEvent");
                if (func and type(func) == "function") then 
                    pcall(func, module, event, ...);
                end
            else
                func(module, ...);
            end
        end
    end
end

local alphabetizedFunc = function(t, last)
    last = tostring(last);
    local nextVal, val;
    for i, v in pairs(t) do
        i = tostring(i);
        if i > last then
            if nextVal then
                if i < nextVal then
                    nextVal = i;
                    val = v;
                end
            else
                nextVal = i;
                val = v;
            end
        end
    end
    return nextVal, val;
end

function AsheylaLib:Alphabetize(t)
    return alphabetizedFunc, t, "";
end

StaticPopupDialogs["ASHEYLALIB"] = {
    text = "%s",
    button1 = "Ok",
    whileDead = 1,
    hideOnEscape = 1,
    timeout = 30,
}
function AsheylaLib:AlertUser(text)
    StaticPopup_Show("ASHEYLALIB", text)
end

local f = CreateFrame("Frame");
f:RegisterEvent("ADDON_LOADED");
f:SetScript("OnEvent", function(self, event, addon)
    if addon == "DoTimer" then
        AsheylaLib.loaded = true;
        local id = UnitName("player") .. "-" .. GetRealmName();
        for name, settings in pairs(AsheylaLib_Settings) do
            if type(settings) == "table" and settings[id] then
                ASHEYLALIB_ACTIVE_PROFILE = name;
                break;
            end
        end
        AsheylaLib_Settings[ASHEYLALIB_ACTIVE_PROFILE] = AsheylaLib_Settings[ASHEYLALIB_ACTIVE_PROFILE] or {};
        for module in pairs(modules) do
            module:UpdateSettings();
        end
    end
end)

local f = CreateFrame("Frame", nil, InterfaceOptionsFrame);
f:SetScript("OnShow", function() LoadAddOn("DoTimer_Options"); end);
